package com.currency.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.currency.constant.MarkCode;
import com.currency.exception.AppException;
import com.currency.mapper.*;
import com.currency.pojo.*;
import com.currency.request.NewTradeRequest;
import com.currency.request.UserIdNormalRequest;
import com.currency.request.WithdrawalOilCardRequest;
import com.currency.response.BaseResponse;
import com.currency.response.NewTradeResponse;
import com.currency.response.NormalResponse;
import com.currency.response.QueryTradeResponse;
import com.currency.service.PayService;
import com.currency.service.TradeService;
import com.currency.util.AppSecret;
import com.currency.util.PayUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.List;

@Service("tradeService")
@Slf4j
public class TradeServiceImpl implements TradeService {
    @Autowired
    private TradeSerialMapper tradeSerialMapper;

    @Autowired
    private PayDetailMapper payDetailMapper;

    @Autowired
    private WithdrawalDetailMapper withdrawalDetailMapper;

    @Autowired
    private PayService payService;

    @Autowired
    private PayAccountMapper payAccountMapper;

    @Autowired
    private WytCoinsTradeResumeMapper resumeMapper;

    @Value("${sys.machineId}")
    private Integer machineId;


    @RequestMapping(value = "/new", method = RequestMethod.POST)
    @ApiOperation("统一支付 / 提现 接口")
    @Transactional(rollbackFor = Exception.class)
    public NewTradeResponse newTrade(@RequestBody @Validated NewTradeRequest request) throws Exception {
        // 考虑允许存在未支付前一单，直接支付下一单的情况
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("user_id", request.getUserId());
//        map.put("trade_status", 1);
//        List<WytCurrencyTradeSerial> tradeSerialData = tradeSerialMapper.selectByMap(map);
//        if (tradeSerialData != null && tradeSerialData.size() > 0) {
//            throw new AppException("cey1016", "存在未完成的订单，请先处理");
//        }
        // 将金额转换为分为单位
        if (StringUtils.equalsIgnoreCase(MarkCode.COINS_TYPE_YUAN, request.getCoinsType())) {
            // 元为单位
            String yuanCoins = PayUtil.yuanToFen(request.getTradeCoins());
            // 改为分为单位
            request.setTradeCoins(yuanCoins);
        }

        WytCurrencyTradeSerial tradeSerial = new WytCurrencyTradeSerial();
        tradeSerial.setTradeId("Trade" + IdUtil.createSnowflake(machineId, 0).nextIdStr());
        tradeSerial.setUserId(request.getUserId());
        tradeSerial.setTradeCoins(Integer.parseInt(request.getTradeCoins()));
        tradeSerial.setTradeRemark(request.getTradeRemark());
        tradeSerial.setTradeType(request.getTradeType());
        tradeSerial.setActualCoins(Integer.parseInt(request.getTradeCoins()));
        if (request.getAgencyId().equals(MarkCode.PAY_TYPE_WX)) {
            // 微信操作流程
            return wxTradeOpt(tradeSerial, request.getTradeType());
        } else {
            // 支付宝操作流程
            return apTradeOpt(tradeSerial, request.getTradeType());
        }
    }

    @GetMapping("/query")
    @ApiOperation(value = "查询交易结果接口，flag 参数为结果期望值后续取消，0-交易成功 1-交易取消")
    public QueryTradeResponse queryTrade(String tradeId, Integer flag) throws Exception {
        return payService.queryTrade(tradeId, flag);
    }

    @GetMapping("/cancel")
    @ApiOperation(value = "取消订单")
    public BaseResponse cancelTrade(String tradeId) throws Exception {
        WytCurrencyTradeSerial tradeSerial = tradeSerialMapper.selectById(tradeId);
        if (tradeSerial.getTradeStatus().intValue() == MarkCode.TRADE_STATUS_APPLY || tradeSerial.getTradeStatus().intValue() == MarkCode.TRADE_STATUS_ING) {
            payService.cancelTrade(tradeSerial);
        } else {
            throw new AppException("cey1017", "订单已经完成");
        }
        // 远程取消订单
        return new BaseResponse("cey0000", "取消完成");
    }

    @GetMapping("/query-history")
    @ApiOperation(value = "查询所有订单交易记录")
    public NormalResponse queryHistory(String userId) {
        QueryWrapper<WytCurrencyTradeSerial> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        List<WytCurrencyTradeSerial> list = tradeSerialMapper.selectList(wrapper);
        NormalResponse response = new NormalResponse();
        response.setErrCode("cey0000");
        response.setErrMsg("查询成功");
        response.setData(list);
        return response;
    }

    @GetMapping("query-pay-status")
    @ApiOperation(value = "根据状态查询订单记录,status 0-支付完成 1- 申请支付 2-支付中 3-已取消")
    public NormalResponse queryPayStatus(String userId, int status) {
        QueryWrapper<WytCurrencyTradeSerial> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("trade_status", status);
        List<WytCurrencyTradeSerial> list = tradeSerialMapper.selectList(wrapper);
        NormalResponse response = new NormalResponse();
        response.setErrCode("cey0000");
        response.setErrMsg("查询成功");
        response.setData(list);
        return response;
    }

    @PostMapping("withdrawal-oilCard")
    @ApiOperation(value = "提现到油卡")
    public BaseResponse withdrawalOilCard(@RequestBody WithdrawalOilCardRequest request) throws AppException {
        // 查询客户信息
        WytCurrencyPayAccountPojo pojo = payAccountMapper.selectById(request.getUserId());
        if (pojo == null || StringUtils.isBlank(pojo.getOilCard())) {
            throw new AppException("cey1000", "客户油卡信息为空，请先绑定油卡");
        }

        BigDecimal bd = new BigDecimal(request.getWithdrawalAmount());
        //金额单位转换
        if (!StringUtils.equalsIgnoreCase(request.getUnit(), "fen")) {
            bd = bd.multiply(new BigDecimal("100"));
        }
        int amount = bd.intValue();
        if (amount > pojo.getUserCoins()) {
            // 提现金额大于余额
            throw new AppException("cey1001", "提现金额大于金币余额");
        }

        pojo.setUserCoins(pojo.getUserCoins() - amount);
        pojo.setOilCoins(pojo.getOilCoins() + amount);
        payAccountMapper.updateById(pojo);

        return new BaseResponse("cey0000", "提现到油卡成功");
    }


    private NewTradeResponse wxTradeOpt(WytCurrencyTradeSerial tradeSerial, Integer optType) throws Exception {
        // 生成微信支付相关参数到最后返回的结果中
        String agencyResponse = "";
        String payId = "Pay" + IdUtil.createSnowflake(machineId, 0).nextIdStr();
        tradeSerial.setAssociatedId(payId);
        tradeSerial.setTradeType(optType);

        NewTradeResponse tradeResponse = new NewTradeResponse();
        //支付流程
        if (optType.equals(MarkCode.TRADE_TYPE_PAY)) {
            agencyResponse = payService.wxPay(payId, tradeSerial.getTradeCoins());
            WytCurrencyPayDetailPojo payDetailPojo = new WytCurrencyPayDetailPojo();
            payDetailPojo.setPayId(payId);
            payDetailPojo.setPayParams("{\"out_trade_no\" : " + payId + "}");
            payDetailPojo.setReturnParams(agencyResponse);
            payDetailPojo.setPayType(MarkCode.PAY_TYPE_WX);
            payDetailMapper.insert(payDetailPojo);
            //生成微信支付参数
            JSONObject wxJo = JSONObject.parseObject(agencyResponse.replace("\\\"", "\""));
            tradeResponse.setExpParams(AppSecret.initWechatParam(wxJo.getString("nonce_str"), wxJo.getString("prepay_id")));
        } else {
            // 赎回时，注意手续费收取
            WytCurrencyWithdrawalDetailPojo wdPojo = new WytCurrencyWithdrawalDetailPojo();
            agencyResponse = payService.wxWithdrawal(payId, tradeSerial.getUserId(), tradeSerial.getTradeCoins());
            wdPojo.setWdlId(payId);
            //待补充
            wdPojo.setWdlParams("{\"out_trade_no\" : " + payId + "}");
            wdPojo.setReturnParams(agencyResponse);
            wdPojo.setWdlType(MarkCode.PAY_TYPE_WX);
            withdrawalDetailMapper.insert(wdPojo);
        }
        tradeSerialMapper.insert(tradeSerial);
        tradeResponse.setErrCode("cey0000");
        tradeResponse.setErrMsg("操作成功");
        tradeResponse.setAgencyResponse(agencyResponse);
        tradeResponse.setTradeId(tradeSerial.getTradeId());
        return tradeResponse;
    }

    private NewTradeResponse apTradeOpt(WytCurrencyTradeSerial tradeSerial, Integer optType) throws Exception {
        // 生成支付宝支付相关参数到最后返回的结果中
        String agencyResponse = "";
        String payId = "Pay" + IdUtil.createSnowflake(machineId, 0).nextIdStr();
        tradeSerial.setAssociatedId(payId);
        tradeSerial.setTradeType(optType);
        //支付流程
        if (optType.equals(MarkCode.TRADE_TYPE_PAY)) {
            agencyResponse = payService.apPay(payId, tradeSerial.getTradeCoins());
            WytCurrencyPayDetailPojo payDetailPojo = new WytCurrencyPayDetailPojo();
            payDetailPojo.setPayId(payId);
            //待补充
            payDetailPojo.setPayParams("{\"out_trade_no\" : " + payId + "}");
            payDetailPojo.setReturnParams(agencyResponse);
            payDetailPojo.setPayType(MarkCode.PAY_TYPE_AP);
            payDetailMapper.insert(payDetailPojo);
        } else {
            //赎回时，注意手续费收取
            WytCurrencyWithdrawalDetailPojo wdPojo = new WytCurrencyWithdrawalDetailPojo();
            agencyResponse = payService.apWithdrawal(payId, tradeSerial.getUserId(), tradeSerial.getTradeCoins());
            wdPojo.setWdlId(payId);
            //待补充
            wdPojo.setWdlParams("{\"out_trade_no\" : " + payId + "}");
            wdPojo.setReturnParams(agencyResponse);
            wdPojo.setWdlType(MarkCode.PAY_TYPE_WX);
            withdrawalDetailMapper.insert(wdPojo);
        }
        tradeSerialMapper.insert(tradeSerial);
        NewTradeResponse tradeResponse = new NewTradeResponse();
        tradeResponse.setErrCode("cey0000");
        tradeResponse.setErrMsg("操作成功");
        tradeResponse.setAgencyResponse(agencyResponse);
        tradeResponse.setTradeId(tradeSerial.getTradeId());
        return tradeResponse;
    }

    @PostMapping("/query-resume")
    @ApiOperation(value = "查询金币交易记录概要")
    public NormalResponse<Page<WytCoinsTradeResumePojo>> queryTradeResume(@RequestBody UserIdNormalRequest request) {
        QueryWrapper<WytCoinsTradeResumePojo> wrapper = new QueryWrapper<>();
        Page<WytCoinsTradeResumePojo> page = new Page<>(request.getPage(), request.getPageSize());
        wrapper.eq("user_id", request.getUserId());
        wrapper.orderByDesc("create_datetime");
        //page = resumeMapper.selectPage(page, wrapper);
        Page<WytCoinsTradeResumePojo> data = resumeMapper.selectPage(page, wrapper);
        NormalResponse<Page<WytCoinsTradeResumePojo>> response = new NormalResponse<>();
        response.setErrCode("cey0000");
        response.setErrMsg("查询成功");
        response.setData(data);
        return response;
    }
}
